/*
	The Raja Toolkit.
	Copyright (C) 2011 Raja-Toolkit Foundation

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 3.0 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef VERTEX_BUFFER_HPP
#define VERTEX_BUFFER_HPP

#include "../types.hpp"
#include "../math/math.hpp"

#include "program.hpp"

namespace raja
{
namespace render
{
struct	program;

struct	resource;
struct	vertex_resource;

struct resource
{
	enum USAGE_TYPE
	{
		UT_STATIC_GPU,					///< static resource data on GPU
		UT_DYNAMIC_GPU,					///< dynamic resource data on GPU/SYS
		UT_DYNAMIC_SYS,					///< dynamic resource data on SYSTEM
	};

	enum RESOURCE_TYPE
	{
		RT_VERTEX,						///< vertex buffer
		RT_PRIMITIVE,					///< primitive(index) buffer
		RT_TEXTURE2,					///< 2d texture
		RT_TEXTURE_CUBE,				///< texture cube
	};

	/// class destructor
	virtual				~resource() {}

	/// returns the size in bytes
	uint32				get_size() const	{ return _size; }

	/// returns the resource usage
	USAGE_TYPE			get_usage() const	{ return _usage; }

	/// returns the resource type
	RESOURCE_TYPE		get_type() const	{ return _type; }

protected:
	/// should be private
	resource() : _type(RT_VERTEX), _id(0), _usage(UT_STATIC_GPU), _size(0) {}

	RESOURCE_TYPE		_type;			///< buffer type
	uint32				_id;			///< buffer id inside the driver
	USAGE_TYPE			_usage;			///< buffer usage
	uint32				_size;			///< buffer size

	/// @section1 resource information (for debugging)
	std::string			_name;			///< resource name (if any)
	std::string			_path_name;		///< resource path (if any)
	/// @endsection1

	friend struct		program;
};

struct vertex_array : public resource
{
	vertex_array(const vertex_declaration &decl, uint32 count);
	~vertex_array();

	const void*			operator[](uint32 id) const		{ return (*__array)[id]; }
	void*				operator[](uint32 id)			{ return (*__array)[id]; }

	const vertex_declaration&	get_declaration() const	{ return __decl; }
	uint32				get_count() const { return __array->get_count(); }

	/// for debugging only
	element_array*		get_element_array() { return __array; }

private:
	element_array*		__array;
	vertex_declaration	__decl;
};

template<typename T>
struct vertex_array_map
{
	///
	///
	vertex_array_map(const std::string& attrib_name, vertex_array *arr) : __attrib_name(attrib_name), __array(arr)
	{
		vertex_declaration::attrib	attr	= arr->get_declaration().get_attrib(attrib_name);
		assert( get_data_type<T>() == attr.get_type() );
		__size		= arr->get_declaration().get_vertex_size();
		__offset	= attr.get_offset();
	}

	const std::string	get_attrib_name() const		{ return __attrib_name; }

	const T&			operator[](uint32 id) const
	{
		const uint8*	offset	= reinterpret_cast<const uint8*>((*__array)[id]);
		const T&		t		= reinterpret_cast<const T&>(offset[__offset]);
		return t;
	}

	T&					operator[](uint32 id)
	{
		uint8*	offset	= reinterpret_cast<uint8*>((*__array)[id]);
		T&		t		= reinterpret_cast<T&>(offset[__offset]);
		return t;
	}

private:
	std::string			__attrib_name;
	vertex_array*		__array;
	uint32				__size;
	uint32				__offset;
};


struct vertex_resource : public resource
{
	vertex_resource(const vertex_array &verts,
					USAGE_TYPE t = UT_STATIC_GPU);

	virtual				~vertex_resource();

	uint32				get_vertex_size() const;
	uint32				get_vertex_count() const;
	const void*			get_vertex_pointer(uint32 idx) const;
	void*				get_vertex_pointer(uint32 idx);
};




}	// namespace render
}	// namespace raja
#endif // VERTEX_BUFFER_HPP
